//
//  vdShader.h
//  Void Dead
//
//  Created by Sidney Just on 23.11.09.
//
//  Copyright © 2009 by Sidney Just
//  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 
//  documentation files (the "Software"), to deal in the Software without restriction, including without limitation 
//  the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, 
//  and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
//  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 
//  INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 
//  PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE 
//  FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 
//  ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//

#import <Foundation/Foundation.h>

#import "vdHeader.h"
#import "vdMisc.h"
#import "vdTexNode.h"
#import "vdEventHandler.h"
#import "vdColor.h"

/**
 * \brief A class that can load and bind shaders.
 
 * This class represents a shader. It also handles the loading, compiling and linking of the shader.
 @remark Shaders are also available when using iPhone OS 2.x or an device that doesnt support OpenGL ES 2.0, the shader loading functions are also available, but
 no OpenGL ES 2.0 only function will be executed due to the void dead fallback mechanism. So you mustn't change your code when you want to use both OpenGL ES versions and shaders.
 @remark If you use the vdShader class, make sure to check if ALLOW_ES2 is definded when calling a OpenGL ES 2.0 only function! Otherwise the application won't 
 * compile under iPhone OS 2.x because the OpenGL ES 2.0 headers won't be loaded. If you compile only for iPhone OS 3.x you don't need this check
 **/
@interface vdShader : NSObject {
	//\cond
	GLuint shader;
	
	vdEngineErrorType lastError;
	
	GLfloat *vertices;
	GLfloat *texCoords;
	
	vdTexNode *texture;
	
	vdColor	*color;
	
	GLfloat *matrix;
	
	int positionsPerVertex;
	
	/**
	 * The delegate of the shader
	 **/
	id delegate;
	
	BOOL isPostProcessingShader;
	//\endcond
}

/**
 * The handle to the shader program
 **/
@property GLuint shader;

/**
 * Pointer to an 4x4 matrix that contains a projection and model matrix for the shader.
 **/
@property GLfloat *matrix;

/**
 * This variable can be used to determine if the shader runs as post processing shader or as node shader.
 @remark If the shader runs as post processing shader, you normally don't need to rotate the view matrix as the rotation
 **/
@property BOOL isPostProcessingShader;

/**
 * The number of coordinates per vertex
 **/
@property int positionsPerVertex;

/**
 * The pointer to the color
 @remark The vdRenderer will pass this automatically, but if you use your own drawing code, you need to pass this by yourself.
 **/
@property vdColor *color;

/**
 * The texture that the shader should use or NULL.
 @remark The vdRenderer will pass this automatically, but if you use your own drawing code, you need to pass this by yourself.
 **/
@property (nonatomic, assign) vdTexNode *texture;

/**
 * The pointer to the vertices array.
 @remark The vdRenderer will pass this automatically, but if you use your own drawing code, you need to pass this by yourself.
 **/
@property GLfloat *vertices;

/**
 * The pointer to the texture coordinates array.
 @remark The vdRenderer will pass this automatically, but if you use your own drawing code, you need to pass this by yourself.
 **/
@property GLfloat *texCoords;

/**
 * The last error of the shader. This value can be:
 * <br>vdNoError There is no error, everything works fine
 * <br>vdShaderUnsupported This indicates that you want to load a shader on an device or OS that doesn't support shaders or OpenGL ES 2.0.
 * <br>vdShaderFailedToCompileVertexShader There was an error while compiling the vertex shader data
 * <br>vdShaderFailedToCompileFragmentShader There was an error while compiling the fragment shader data
 * <br>vdShaderFailedToLinkShader There was an error while linking the shader program
 * <br>vdShaderFailedToLoadVertexShader There was an error while loading the vertex shader
 @remark Every error will be thrown by the vdEventHandler and afterwards switched back to vdNoError!
 **/
@property vdEngineErrorType lastError;

/**
 * Loads a shader from the main bundle. You mustn't add the file suffix, the shader will load the .fsh and .vsh files with the given name
 @param shdFile The filename of the .fsh and .vsh files of the shader.
 @return YES if the shader has been successful loaded or NO
 **/
- (BOOL)loadShader:(NSString *)shdFile;

/**
 * Loads a shader from two strings or from the main bundle.
 @param fShader String that contains the fragment shader data or filename with suffix of the file which contains the fragment shader
 @param vShader String that contains the vertex shader data or filename with suffix of the file which contains the vertex shader
 @param hdd If this is set to YES, the shader data will be loaded from the main bundle. If NO, the shader assumes that the shader data is inside the two strings.
 @return YES if the shader has been successful loaded or NO
 **/
- (BOOL)loadVertexShader:(NSString *)vShader andFragmentShader:(NSString *)fShader fromHDD:(BOOL)hdd;

/**
 * Sets the delegate for the shader. If the delegate implements the vdShaderProtocol protocol, the shader will call the functions from the protocol and sends self as sender!
 @remark The delegate must be set before calling loadShader: or loadFragmentShader: andVertexShader: if you want to receive the bindAttributeLocations: and getUniformLocations: messages
 **/
- (void)setDelegate:(id)del;

/**
 * This function will be called before linking the shader, so you can bind attribute locations.
 @remark If the function isn't overwritten, it will call the delegates bindAttributeLocations: function (if an delegate exist)
 **/
- (void)bindAttributeLocations;

/**
 * This function will be called after linking the shader, so you get uniform locations (and also attribute locations)
 @remark If the function isn't overwritten, it will call the delegates getUniformLocations: function (if an delegate exist)
 **/
- (void)getUniformLocations;

/**
 * This function will be called from the vdRenderer after it has activated the shader via glUseProgram. Her you can enable your attributes, passing variables to the uniforms and so on.
 @remark There is no need of calling glDrawArray or glDrawElements, this will be done by the vdRenderer!
 **/
- (void)runShader;

@end

/**
 * This protocol implements the three main functions for shaders.
 * <br> If the shader has a delegate and the delegate implements this protocol, all implemented functions of the protocol will be fired.
 **/
@protocol vdShaderProtocol
@optional
/**
 * This function will be called before linking the shader, so you can bind attribute locations.
 @param sender The shader that will be linked
 **/
- (void)bindAttributeLocations:(vdShader *)sender;
/**
 * This function will be called after linking the shader, so you get uniform locations (and also attribute locations)
 @param sender The shader that has been linked
 **/
- (void)getUniformLocations:(vdShader *)sender;
/**
 * This function will be called from the vdRenderer after it has activated the shader via glUseProgram. Her you can enable your attributes, passing variables to the uniforms and so on.
 @param sender The shader that has been enabled and will be used for the rendering
 @remark There is no need of calling glDrawArray or glDrawElements, this will be done by the vdRenderer!
 **/
- (void)runShader:(vdShader *)sender;
@end

